package com.syqc.netlib

import com.syqc.netlib.errorhandler.SingleHttpErrorHandler
import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers
import io.reactivex.rxjava3.core.SingleTransformer
import io.reactivex.rxjava3.functions.Function
import io.reactivex.rxjava3.schedulers.Schedulers
import okhttp3.Interceptor
import okhttp3.OkHttpClient
import retrofit2.Retrofit
import retrofit2.adapter.rxjava3.RxJava3CallAdapterFactory
import retrofit2.converter.gson.GsonConverterFactory
import retrofit2.converter.scalars.ScalarsConverterFactory
import java.util.concurrent.TimeUnit

abstract class NetWorkApi : IBaseUrl {
    private val retrofitHashMap: HashMap<String, Retrofit> = HashMap()
    private val retrofitMap: HashMap<String, Retrofit> = HashMap()
    private val clientMap: HashMap<String, OkHttpClient> = HashMap()
    private lateinit var mBaseUrl: String
    private var isDebug = true
    //是否开启Https请求
//    private var isHttps = false

    fun init(isDebug: Boolean) {
        this.isDebug = isDebug
        mBaseUrl = if (isDebug) {
            testUrl()
        } else {
            formalUrl()
        }
    }

    fun changeUrl() {
        mBaseUrl = if (isDebug) {
            testUrl()
        } else {
            formalUrl()
        }
        retrofitMap.clear()
        retrofitHashMap.clear()
    }

    protected fun <T> getRetrofit(
        clazz: Class<T>,
        url: String = mBaseUrl,
        time: Int
    ): Retrofit {
        val key = url + clazz.name + time
        if (retrofitMap[key] != null)
            return retrofitMap[key]!!
        val retrofit = Retrofit.Builder().apply {
            baseUrl(url)
            client(getOkHttpClient(time.toLong()))
            addConverterFactory(ScalarsConverterFactory.create())
            addConverterFactory(GsonConverterFactory.create())
            addCallAdapterFactory(RxJava3CallAdapterFactory.create())
        }.build()

        retrofitMap[key] = retrofit
        return retrofit
    }

    /**
     * 无公共参数 无Gson转换
     */
    protected fun <T> getRetrofitNoParams(
        clazz: Class<T>,
        url: String = mBaseUrl,
    ): Retrofit {
        val key = url + clazz.name
        if (retrofitHashMap[key] != null)
            return retrofitHashMap[key]!!
        val retrofit = Retrofit.Builder().apply {
            baseUrl(url)
            client(getHttpClient())
            addConverterFactory(ScalarsConverterFactory.create())
            if (url == mBaseUrl) {
                addConverterFactory(GsonConverterFactory.create())
            }
            addCallAdapterFactory(RxJava3CallAdapterFactory.create())
        }.build()
        retrofitHashMap[key] = retrofit
        return retrofit
    }

    /**
     * 无公共参数 无Gson转换
     */
    protected fun <T> getRetrofitParams(clazz: Class<T>, url: String): Retrofit {
        if (retrofitHashMap[url + clazz.name] != null)
            return retrofitHashMap[url + clazz.name]!!
        val retrofit = Retrofit.Builder().apply {
            baseUrl(url)
            client(getHttpClient())
            addConverterFactory(ScalarsConverterFactory.create())
            addConverterFactory(GsonConverterFactory.create())
            addCallAdapterFactory(RxJava3CallAdapterFactory.create())
        }.build()
        retrofitHashMap[url + clazz.name] = retrofit
        return retrofit
    }


    private fun getOkHttpClient(time: Long): OkHttpClient {
        var client = clientMap[time.toString()]
        if (client == null) {
            client = OkHttpClient.Builder().apply {
                getInterceptor()?.let {
                    addInterceptor(it)
                }
                if (isDebug) {
                    addInterceptor(HttpLoggingInterceptor().apply {
                        level = HttpLoggingInterceptor.Level.BODY
                    })
                }
                connectTimeout(time, TimeUnit.SECONDS)//设置连接超时时间
                readTimeout(time, TimeUnit.SECONDS)//设置读取超时时间
                writeTimeout(time, TimeUnit.SECONDS)//设置写数据超时时间

            }.build()
            clientMap[time.toString()] = client
        }
        return client
    }


    private fun getHttpClient(): OkHttpClient {
        return OkHttpClient.Builder().apply {
            if (isDebug) {
                addInterceptor(HttpLoggingInterceptor().apply {
                    level = HttpLoggingInterceptor.Level.BODY
                })
            }
            connectTimeout(30, TimeUnit.SECONDS)//设置连接超时时间
            readTimeout(30, TimeUnit.SECONDS)//设置读取超时时间
            writeTimeout(30, TimeUnit.SECONDS)//设置写数据超时时间
        }.build()
    }


    fun <T : Any> applySingleSchedulers(): SingleTransformer<T, T> {
        return SingleTransformer { upstream ->
            upstream.subscribeOn(Schedulers.io())
                .map(getAppErrorHandler())
                .observeOn(AndroidSchedulers.mainThread())
                .onErrorResumeNext(SingleHttpErrorHandler<T>())
        }
    }


    fun <T : Any> applyNoMapSingleSchedulers(): SingleTransformer<T, T> {
        return SingleTransformer { upstream ->
            upstream.subscribeOn(Schedulers.io())
                .observeOn(AndroidSchedulers.mainThread())
                .onErrorResumeNext(SingleHttpErrorHandler<T>())
        }
    }

    abstract fun <T : Any> getAppErrorHandler(): Function<T, T>

    abstract fun getInterceptor(): Interceptor?


}